package com.djakapm.markdown.editor;

import com.djakapm.markdown.editor.action.*;
import com.djakapm.markdown.editor.component.AppFileFilter;
import com.djakapm.markdown.editor.component.EditorComponentPresenter;
import com.djakapm.markdown.editor.component.EditorComponentView;
import com.djakapm.markdown.editor.util.ConfigManager;
import com.djakapm.markdown.editor.util.ExceptionConsumer;
import com.djakapm.markdown.editor.util.ResourceManager;
import com.djakapm.swing.common.ContainerFactory;
import com.djakapm.swing.common.ScreenUtil;
import com.djakapm.swing.component.tab.Tab;
import com.djakapm.swing.container.BorderPanel;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.io.FilenameUtils;

import javax.swing.*;
import java.awt.event.InputEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class Application{
    private Action openFileAction;
    private Action newFileAction;
    private Action exitApplicationAction;
    private Action markdownSyntaxHelpAction;
    private Action closeFileAction;
    private JFileChooser fileDialog;
    private Tab contentTabPane;
    private List<EditorComponentPresenter> editorComponentList = new ArrayList<EditorComponentPresenter>();
    private boolean needPromptingToSaveFileBeforeClose;
    private JFrame frame;


    public Application(){
        this.createFileDialog();
    }

    private void createTab(){
        this.contentTabPane = new Tab();
        this.contentTabPane.setDefaultCloseOperation(false);
        this.contentTabPane.setClosable(true);
        this.contentTabPane.setAfterTabCloseAction(this.closeFileAction);
    }

    private void createActions(){
        this.openFileAction = new OpenFileAction(this);
        this.newFileAction = new NewFileAction(this);
        this.exitApplicationAction = new ExitApplicationAction(this);
        this.markdownSyntaxHelpAction = new MarkdownSyntaxHelpAction();
        this.closeFileAction = new CloseFileAction(this);
    }

    private void createFileDialog(){
        this.fileDialog = new JFileChooser();
        this.fileDialog.setFileFilter(new AppFileFilter());
        this.fileDialog.setAcceptAllFileFilterUsed(false);
    }

    public boolean isContentModifiedAt(int selectedIndex){
        return this.editorComponentList.get(selectedIndex).isContentModified();
    }

    public void saveContentAt(int selectedIndex){
        this.editorComponentList.get(selectedIndex).saveContent();
    }

    public void removeContent(int selectedIndex){
        this.editorComponentList.remove(selectedIndex);
    }
    
    public void addContent(){
        EditorComponentPresenter presenter = new EditorComponentPresenter(this.contentTabPane);
        this.editorComponentList.add(presenter);
        this.addContentToTab(AppConstant.NEW_FILE_TITLE,AppConstant.NEW_FILE_TITLE,presenter.getView());
    }

    public void addContent(File contentFile){
        EditorComponentPresenter presenter = new EditorComponentPresenter(this.contentTabPane,contentFile);
        this.editorComponentList.add(presenter);
        this.addContentToTab(FilenameUtils.getName(contentFile.getPath()),contentFile.getPath(),presenter.getView());
    }

    private void addContentToTab(String title,String tooltip, EditorComponentView ec){
        int idx = this.editorComponentList.size()-1;
        ec.setIndex(idx);
        this.contentTabPane.add(title,ec);
        this.contentTabPane.setToolTipTextAt(idx,tooltip);
        this.contentTabPane.setSelectedIndex(idx);
    }
    
    public void openContent(){
        int result = this.fileDialog.showOpenDialog(null);

        if(result != JFileChooser.APPROVE_OPTION){return;}

        if(this.fileDialog.getSelectedFile() == null){
            return;
        }
        this.addContent(this.fileDialog.getSelectedFile());
    }

    public boolean init(String[] args){
        BorderPanel contentPane = ContainerFactory.newBorderLayoutedPanel();
        boolean initialized = false;
        JToolBar toolbar = new JToolBar();

        if(args == null || args.length == 0){throw new RuntimeException(AppConstant.NOARGUMENT_ERROR);}
        
        try {
            ConfigManager.init(args[0]);
            ResourceManager.init();
        } catch (ConfigurationException e) {
            ExceptionConsumer.consume(e); 
        }

        this.createActions();
        this.createTab();



        this.frame = ContainerFactory.newFrame(AppConstant.APP_NAME);
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu(AppConstant.FILE_LABEL);

        fileMenu.add(this.newFileAction);
        fileMenu.add(this.openFileAction);
        fileMenu.add(this.exitApplicationAction);

        JMenu helpMenu = new JMenu(AppConstant.HELP_LABEL);
        helpMenu.add(this.markdownSyntaxHelpAction);
        menuBar.add(fileMenu);
        menuBar.add(helpMenu);
        this.frame.setJMenuBar(menuBar);


        this.frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        this.frame.addWindowListener(new CloseApplicationEvent(this));

        toolbar.add(this.openFileAction);
        toolbar.add(this.newFileAction);
        contentPane.addToNorth(toolbar).addToCenter(this.constructUserInterface());

        contentPane.getActionMap().put(AppConstant.NEW_FILE_ACTION,this.newFileAction);
        contentPane.getActionMap().put(AppConstant.OPEN_FILE_ACTION,this.openFileAction);

        contentPane.getInputMap().put(KeyStroke.getKeyStroke('O', InputEvent.CTRL_MASK),AppConstant.OPEN_FILE_ACTION);
        contentPane.getInputMap().put(KeyStroke.getKeyStroke('N', InputEvent.CTRL_MASK),AppConstant.NEW_FILE_ACTION);

        this.frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        this.frame.setContentPane(contentPane);
        ScreenUtil.center(this.frame);
        this.frame.setVisible(true);

        if(this.frame.isVisible()){
            initialized = true;
        }

        return initialized;
    }

    private Tab constructUserInterface(){
        this.contentTabPane.add(AppConstant.NEW_FILE_TITLE,new EditorComponentView(this.contentTabPane));
        this.contentTabPane.removeAll();
        return this.contentTabPane;
    }


    public static void main(String[] args) {
        Application application = new Application();
        application.init(args);
    }

    public void exit(){
        int size = this.editorComponentList.size();

        for(int idx=0;idx<size;idx++){
            boolean isModified = this.isContentModifiedAt(idx);
            if(isModified){
                needPromptingToSaveFileBeforeClose = true;
                break;
            }
        }

        if(needPromptingToSaveFileBeforeClose){
            int result = JOptionPane.showConfirmDialog(null,AppConstant.CONFIRM_EXIT_LABEL,
                    AppConstant.CONFIRM_EXIT_TITLE_LABEL,JOptionPane.YES_NO_OPTION);
            switch(result){
                case JOptionPane.NO_OPTION:
                    needPromptingToSaveFileBeforeClose = false;
                    break;
                case JOptionPane.YES_OPTION:
                    frame.dispose();
                    break;
            }
        }
        else{
            frame.dispose();
            System.exit(0);
        }
    }

}
